/**
 * 打包应用脚本
 */
const fs = require('fs-extra');
const path = require('path');
const ora = require('ora');
const archiver = require('archiver');
const {checkAppConfig} = require("./common");

// 工作目录
const WORK_DIR = process.cwd();

/**
 * 打包应用
 * @param {string} [appDir] 应用目录
 * @returns {Promise<Object>} 打包结果
 */
async function buildApp(appDir) {
    const spinner = ora('准备打包应用...').start();

    try {
        appDir = appDir || WORK_DIR;

        // 检查应用目录是否存在
        if (!fs.existsSync(appDir)) {
            throw new Error(`应用目录不存在: ${appDir}`);
        }

        // 检查应用配置
        const appConfigPath = path.join(appDir, 'app.json');
        if (!fs.existsSync(appConfigPath)) {
            throw new Error('应用配置文件不存在');
        }

        const appConfig = await fs.readJSON(appConfigPath);
        checkAppConfig(appConfig);

        // 检查要打包的目录
        const packageDir = path.join(appDir, appConfig.package.packageDir);
        if (!fs.existsSync(packageDir)) {
            throw new Error(`packageDir目录不存在: ${packageDir}`);
        }

        // 打包
        spinner.text = '开始打包...';
        const buildOutDir = path.join(WORK_DIR, appConfig.package.buildOutDir);
        fs.ensureDirSync(buildOutDir);

        const zipPath = path.join(buildOutDir, `${appConfig.name}-${appConfig.version}.stapp`);

        // 创建临时目录用于打包
        const tempDir = path.join(buildOutDir, 'temp');
        await fs.ensureDir(tempDir);

        // 复制构建输出目录内容
        await fs.copy(packageDir, path.join(tempDir, 'src'));

        // 复制 app.json
        await fs.copy(appConfigPath, path.join(tempDir, 'app.json'));

        // 创建压缩包
        await createZipArchive(tempDir, zipPath);

        // 清理临时目录
        await fs.remove(tempDir);

        spinner.succeed(`应用打包成功! 版本: ${appConfig.version}`);

        return {
            appDir,
            version: appConfig.version
        };
    } catch (err) {
        spinner.fail(`打包失败: ${err.message}`);
        throw err;
    }
}

/**
 * 创建ZIP压缩包
 * @param {string} sourceDir 源目录
 * @param {string} outputPath 输出文件路径
 * @returns {Promise<void>}
 */
function createZipArchive(sourceDir, outputPath) {
    return new Promise((resolve, reject) => {
        // 创建文件流
        const output = fs.createWriteStream(outputPath);
        const archive = archiver('zip', {
            zlib: { level: 9 } // 最高压缩级别
        });

        // 监听关闭事件
        output.on('close', () => {
            resolve();
        });

        // 监听错误
        archive.on('error', (err) => {
            reject(err);
        });

        // 管道连接
        archive.pipe(output);

        // 添加目录到压缩包
        archive.directory(sourceDir, false);

        // 完成归档
        archive.finalize();
    });
}

module.exports = {
    buildApp
};
